package com.rnkrsoft.suyan.config.server.services.impl;

import com.rnkrsoft.framework.orm.Order;
import com.rnkrsoft.suyan.config.internal.enums.*;
import com.rnkrsoft.suyan.config.protocol.v2.ConfigResponseCode;
import com.rnkrsoft.suyan.config.protocol.v2.DataTypeEnum;
import com.rnkrsoft.suyan.config.protocol.v2.ParamType;
import com.rnkrsoft.suyan.config.server.config.dao.*;
import com.rnkrsoft.suyan.config.server.config.entity.*;
import com.rnkrsoft.suyan.config.server.services.guide.domains.*;
import com.rnkrsoft.suyan.config.server.services.guide.services.ConfigGuideService;
import com.rnkrsoft.suyan.config.server.services.logger.services.LoggerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.UUID;

/**
 * Created by woate on 2019/6/26.
 */
@Service
public class ConfigGuideServiceImpl implements ConfigGuideService {
    @Autowired
    ProjectInfoDAO projectDAO;
    @Autowired
    ProjectDependencyDAO projectDependencyDAO;
    @Autowired
    VersionInfoDAO versionInfoDAO;
    @Autowired
    EnvironmentInfoDAO environmentDAO;
    @Autowired
    MachineInfoDAO machineDAO;
    @Autowired
    ParamInfoDAO paramDAO;
    @Autowired
    AuthorityInfoDAO authorityDAO;
    @Autowired
    LoggerService loggerService;

    @Override
    public FetchProjectResponse fetchProject(FetchProjectRequest request) {
        FetchProjectResponse response = new FetchProjectResponse();
        List<ProjectInfoEntity> projectInfoEntities = projectDAO.selectAnd(ProjectInfoEntity.builder()
                        .projectStatus(ProjectStatusEnum.NORMAL.getCode())
                        .build()
        );
        for (ProjectInfoEntity projectInfoEntity : projectInfoEntities) {
            String projectDesc = projectInfoEntity.getProjectDesc();
            FetchProjectRecord record = FetchProjectRecord.builder()
                    .groupId(projectInfoEntity.getGroupId())
                    .artifactId(projectInfoEntity.getArtifactId())
                    .projectDesc(projectDesc)
                    .projectId(projectInfoEntity.getProjectId())
                    .abstractProject(projectInfoEntity.getAbstractProject())
                    .build();
            response.addRecord(record);
        }
        return response;
    }

    @Override
    public FetchProjectVersionResponse fetchProjectVersion(FetchProjectVersionRequest request) {
        FetchProjectVersionResponse response = new FetchProjectVersionResponse();
        List<VersionInfoEntity> versionInfoEntities = versionInfoDAO.selectAnd(VersionInfoEntity.builder()
                .projectId(request.getProjectId())
                .build());
        for (VersionInfoEntity versionInfoEntity : versionInfoEntities) {
            FetchProjectVersionRecord record = FetchProjectVersionRecord.builder()
                    .versionId(versionInfoEntity.getVersionId())
                    .version(versionInfoEntity.getVersion())
                    .build();
            response.addRecord(record);
        }
        return response;
    }

    @Override
    public FetchEnvironmentResponse fetchEnvironment(FetchEnvironmentRequest request) {
        FetchEnvironmentResponse response = new FetchEnvironmentResponse();
        List<EnvironmentInfoEntity> environmentInfoEntities = environmentDAO.selectAnd(EnvironmentInfoEntity.builder()
                .versionId(request.getVersionId())
                .build());
        for (EnvironmentInfoEntity environmentInfoEntity : environmentInfoEntities) {
            FetchEnvironmentRecord record = FetchEnvironmentRecord.builder()
                    .environmentId(environmentInfoEntity.getEnvironmentId())
                    .environmentName(environmentInfoEntity.getEnvironmentName())
                    .environmentType(environmentInfoEntity.getEnvironmentType())
                    .build();
            response.addRecord(record);
        }
        return response;
    }

    @Override
    public FetchMachineResponse fetchMachine(FetchMachineRequest request) {
        FetchMachineResponse response = new FetchMachineResponse();
        List<MachineInfoEntity> machineInfoEntities = machineDAO.selectAnd(MachineInfoEntity.builder()
                        .environmentId(request.getEnvironmentId())
                        .build()
        );
        for (MachineInfoEntity machineInfoEntity : machineInfoEntities) {
            FetchMachineRecord record = FetchMachineRecord.builder()
                    .machineId(machineInfoEntity.getMachineId())
                    .machineName(machineInfoEntity.getMachineName())
                    .machineDesc(machineInfoEntity.getMachineDesc())
                    .build();
            response.addRecord(record);
        }
        return response;
    }

    @Override
    public FetchParamResponse fetchParam(FetchParamRequest request) {
        FetchParamResponse response = new FetchParamResponse();
        ParamInfoEntity paramEntity = ParamInfoEntity.builder()
                .machineId(request.getMachineId())
                .build();
        paramEntity.addOrderBy("PARAM_NAME", Order.ASC);
        MachineInfoEntity machineEntity = machineDAO.selectByPrimaryKey(request.getMachineId());
        if (machineEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        EnvironmentInfoEntity environmentInfoEntity = environmentDAO.selectByPrimaryKey(machineEntity.getEnvironmentId());
        if (environmentInfoEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        VersionInfoEntity versionInfoEntity = versionInfoDAO.selectByPrimaryKey(environmentInfoEntity.getVersionId());
        if (versionInfoEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        ProjectInfoEntity projectInfoEntity = projectDAO.selectByPrimaryKey(versionInfoEntity.getProjectId());
        if (projectInfoEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        List<ParamInfoEntity> paramEntities = paramDAO.selectAllParams(projectInfoEntity.getProjectId(), versionInfoEntity.getVersion(), environmentInfoEntity.getEnvironmentName(), machineEntity.getMachineName());
        for (ParamInfoEntity paramInfoEntity : paramEntities) {
            String paramValue = null;
            YesOrNo hasAuthority = YesOrNo.Y;
            //查询当前用户是否拥有权限
            if (1 == authorityDAO.hasAuthorityOnParam(paramInfoEntity.getParamId(), request.getLoginUserId())) {
                paramValue = paramInfoEntity.getParamValue();
                hasAuthority = YesOrNo.Y;
            } else {
                hasAuthority = YesOrNo.N;
            }
            int paramDataType = paramInfoEntity.getParamDataType();
            String paramDesc = paramInfoEntity.getParamDesc();
            FetchParamRecord record = FetchParamRecord.builder()
                    .paramId(paramInfoEntity.getParamId())
                    .paramAuthority(hasAuthority.getCode())
                    .paramName(paramInfoEntity.getParamName())
                    .paramExtends(paramInfoEntity.getParamExtends())
                    .paramValue(paramValue)
                    .paramDataType(paramDataType)
                    .paramType(paramInfoEntity.getParamType())
                    .paramDesc(paramDesc)
                    .build();
            response.addRecord(record);
        }
        return response;
    }

    @Override
    public CreateParamResponse createParam(CreateParamRequest request) {
        CreateParamResponse response = new CreateParamResponse();
        MachineInfoEntity machineEntity = machineDAO.selectByPrimaryKey(request.getMachineId());
        if (machineEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        EnvironmentInfoEntity environmentInfoEntity = environmentDAO.selectByPrimaryKey(machineEntity.getEnvironmentId());
        if (environmentInfoEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        VersionInfoEntity versionInfoEntity = versionInfoDAO.selectByPrimaryKey(environmentInfoEntity.getVersionId());
        if (versionInfoEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        ProjectInfoEntity projectInfoEntity = projectDAO.selectByPrimaryKey(versionInfoEntity.getProjectId());
        if (projectInfoEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        List<ParamInfoEntity> paramEntities = paramDAO.selectAnd(ParamInfoEntity.builder()
                .machineId(machineEntity.getMachineId())
                .paramName(request.getParamName())
                .build());
        if (!paramEntities.isEmpty()) {
            response.updateResult(ConfigResponseCode.NO_DATA.getCode(),"参数名'" + request.getParamName() + "'的参数已经存在！");
            return response;
        }
        String paramName = request.getParamName();
        String paramValue = null;
        ParamType paramType = null;
        DataTypeEnum dataType = null;
        YesOrNo paramExtends = YesOrNo.N;
        //如果项目是抽象项目
        if (YesOrNo.valueOfCode(projectInfoEntity.getAbstractProject()) == YesOrNo.Y) {
            paramExtends = YesOrNo.N;
            paramValue = request.getParamValue();
            paramType = ParamType.valueOfCode(request.getParamType());
            dataType = DataTypeEnum.valueOfCode(request.getParamDataType());
            if (dataType == DataTypeEnum.BOOLEAN) {
                if (!"true".equals(paramValue) && !"false".equals(paramValue)) {
                    response.updateResult(ConfigResponseCode.NO_DATA.getCode(),"参数类型为布尔值，请输入true/false");
                    return response;
                }
            } else if (dataType == DataTypeEnum.INTEGER) {
                if (!paramValue.matches("^\\d+$")) {
                    response.updateResult(ConfigResponseCode.NO_DATA.getCode(),"参数类型为整数值，请输入有效的整数值");
                    return response;
                }

                if (Integer.valueOf(paramValue) < Integer.MIN_VALUE || Integer.valueOf(paramValue) > Integer.MAX_VALUE) {
                    response.updateResult(ConfigResponseCode.NO_DATA.getCode(),"参数类型为整数值，数据越界");
                    return response;
                }
            }
        } else {
            //获取继承的参数对象
            ParamInfoEntity extendsParam = paramDAO.selectExtendParamByGavemp(projectInfoEntity.getProjectId(), versionInfoEntity.getVersion(), environmentInfoEntity.getEnvironmentName(), machineEntity.getMachineName(), request.getParamName());
            if (extendsParam != null) {
                paramExtends = YesOrNo.Y;
                paramValue = "";
                paramType = ParamType.valueOfCode(extendsParam.getParamType());
                dataType = DataTypeEnum.valueOfCode(extendsParam.getParamDataType());
            } else {//如果参数不存在继承参数
                paramExtends = YesOrNo.N;
                paramValue = request.getParamValue();
                paramType = ParamType.valueOfCode(request.getParamType());
                dataType = DataTypeEnum.valueOfCode(request.getParamDataType());
                if (dataType == DataTypeEnum.BOOLEAN) {
                    if (!"true".equals(paramValue) && !"false".equals(paramValue)) {
                        response.updateResult(ConfigResponseCode.NO_DATA.getCode(),"参数类型为布尔值，请输入true/false");
                        return response;
                    }
                } else if (dataType == DataTypeEnum.INTEGER) {
                    if (!paramValue.matches("^\\d+$")) {
                        response.updateResult(ConfigResponseCode.NO_DATA.getCode(),"参数类型为整数值，请输入有效的整数值");
                        return response;
                    }

                    if (Integer.valueOf(paramValue) < Integer.MIN_VALUE || Integer.valueOf(paramValue) > Integer.MAX_VALUE) {
                        response.updateResult(ConfigResponseCode.NO_DATA.getCode(),"参数类型为整数值，数据越界");
                        return response;
                    }
                }
            }
        }
        ParamInfoEntity paramEntity = ParamInfoEntity.builder()
                .projectId(machineEntity.getProjectId())
                .versionId(machineEntity.getVersionId())
                .environmentId(machineEntity.getEnvironmentId())
                .machineId(machineEntity.getMachineId())
                .paramName(paramName)
                .paramExtends(paramExtends.getCode())
                .paramValue(paramValue)
                .paramDataType(dataType.getCode())
                .paramType(paramType.getCode())
                .paramDesc(request.getParamDesc())
                .paramDynamic(YesOrNo.Y.getCode())
                .paramEncrypt(request.getParamEncrypt())
                .paramSystemProperties(YesOrNo.Y.getCode())
                .paramStatus(ParamStatusEnum.NORMAL.getCode())
                .paramVersion(1)
                .paramCreator(request.getLoginUserId())
                .paramLastUpdater(request.getLoginUserId())
                .build();
        paramDAO.insertSelective(paramEntity);
        response.setParamId(paramEntity.getParamId());
        //对于自己创建的参数可以授权
        authorityDAO.insertSelective(AuthorityInfoEntity.builder()
                        .resourceId(paramEntity.getParamId())
                        .resourceType(ResourceTypeEnum.PARAM.getCode())
                        .userId(request.getLoginUserId())
                        .userName(request.getLoginUserName())
                        .createOperatorId(request.getLoginUserId())
                        .createOperatorName(request.getLoginUserName())
                        .build()
        );
        //刷新机器的更新时间
        machineDAO.updateByPrimaryKeySelective(machineEntity);
        return response;
    }

    @Override
    public DeleteParamResponse deleteParam(DeleteParamRequest request) {
        DeleteParamResponse response = new DeleteParamResponse();
        //查询当前用户是否拥有权限
        if (0 == authorityDAO.hasAuthorityOnParam(request.getParamId(), request.getLoginUserId())) {
            response.updateResult(ConfigResponseCode.NOT_AUTHORITY);
            return response;
        }
        //记录快照日志
        loggerService.writeLog(OperateObjectEnum.PARAM, request.getParamId(), OperateTypeEnum.DELETE, request.getLoginUserId(), request.getLoginUserName());
        int updateCount = paramDAO.deleteByPrimaryKey(request.getParamId());
        if (updateCount == 1) {
            return response;
        } else {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
    }

    @Override
    public BatchUpdateParamResponse batchUpdateParam(BatchUpdateParamRequest request) {
        BatchUpdateParamResponse response = new BatchUpdateParamResponse();
        MachineInfoEntity machineEntity = machineDAO.selectByPrimaryKey(request.getMachineId());
        if (machineEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        //记录快照日志
        loggerService.writeLog(OperateObjectEnum.MACHINE, machineEntity.getMachineId(), OperateTypeEnum.UPDATE, request.getLoginUserId(), request.getLoginUserName());
        for (BatchUpdateParamRecord record : request.getRecords()) {
            ParamInfoEntity paramEntity = paramDAO.selectByPrimaryKey(record.getParamId());
            //如果参数没有权限
            if (0 == authorityDAO.hasAuthorityOnParam(record.getParamId(), request.getLoginUserId())) {
                response.updateResult(ConfigResponseCode.NOT_AUTHORITY);
                return response;
            }
            if (YesOrNo.valueOfCode(paramEntity.getParamExtends()) == YesOrNo.Y) {
                response.updateResult(ConfigResponseCode.NO_DATA.getCode(),"参数" + paramEntity.getParamName() + "为继承参数，不允许修改");
                return response;
            } else {
                ParamInfoEntity updateEntity = new ParamInfoEntity();
                updateEntity.setParamId(paramEntity.getParamId());
                updateEntity.setParamDataType(record.getParamDataType());
                updateEntity.setParamVersion(paramEntity.getParamVersion() + 1);
                updateEntity.setParamValue(record.getParamValue());
                updateEntity.setParamDesc(record.getParamDesc());
                updateEntity.setParamLastUpdater(request.getLoginUserId());
                int updateCount = paramDAO.updateByPrimaryKeySelective(updateEntity);
                if (updateCount != 1) {
                    response.updateResult(ConfigResponseCode.NO_DATA);
                    return response;
                }
            }
        }
        return response;
    }

    @Override
    public CreateEnvironmentResponse createEnvironment(CreateEnvironmentRequest request) {
        CreateEnvironmentResponse response = new CreateEnvironmentResponse();
        VersionInfoEntity versionInfoEntity = versionInfoDAO.selectByPrimaryKey(request.getVersionId());
        if (versionInfoEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        EnvironmentInfoEntity environmentEntity = EnvironmentInfoEntity.builder()
                .versionId(versionInfoEntity.getVersionId())
                .projectId(versionInfoEntity.getProjectId())
                .environmentType(request.getEnvironmentType())
                .environmentName(request.getEnvironmentName())
                .environmentStatus(EnvironmentStatusEnum.NORMAL.getCode())
                .build();
        environmentDAO.insertSelective(environmentEntity);
        response.setEnvironmentId(environmentEntity.getEnvironmentId());
        return response;
    }

    @Override
    public DeleteEnvironmentResponse deleteEnvironment(DeleteEnvironmentRequest request) {
        DeleteEnvironmentResponse response = new DeleteEnvironmentResponse();
        int paramCount = paramDAO.countAnd(ParamInfoEntity.builder().environmentId(request.getEnvironmentId()).build());
        int hasAuthorityCount = authorityDAO.hasAuthorityOnEnvironment(request.getEnvironmentId(), request.getLoginUserId());
        if (paramCount != hasAuthorityCount) {
            response.updateResult(ConfigResponseCode.NOT_AUTHORITY);
            return response;
        }
        //记录快照日志
        loggerService.writeLog(OperateObjectEnum.ENVIRONMENT, request.getEnvironmentId(), OperateTypeEnum.DELETE, request.getLoginUserId(), request.getLoginUserName());
        environmentDAO.deleteByPrimaryKey(request.getEnvironmentId());
        machineDAO.deleteAnd(MachineInfoEntity.builder().environmentId(request.getEnvironmentId()).build());
        paramDAO.deleteAnd(ParamInfoEntity.builder().environmentId(request.getEnvironmentId()).build());
        return response;
    }

    @Override
    public CreateMachineResponse createMachine(CreateMachineRequest request) {
        CreateMachineResponse response = new CreateMachineResponse();
        EnvironmentInfoEntity environmentEntity = environmentDAO.selectByPrimaryKey(request.getEnvironmentId());
        if (environmentEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        List<MachineInfoEntity> machineEntities = machineDAO.selectAnd(MachineInfoEntity.builder()
                        .environmentId(environmentEntity.getEnvironmentId())
                        .machineName(request.getMachineName())
                        .build()
        );
        if (!machineEntities.isEmpty()) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        MachineInfoEntity machineEntity = MachineInfoEntity.builder()
                .projectId(environmentEntity.getProjectId())
                .versionId(environmentEntity.getVersionId())
                .environmentId(environmentEntity.getEnvironmentId())
                .machineName(request.getMachineName())
                .machineDesc(request.getMachineDesc())
                .machineStatus(MachineStatusEnum.NORMAL.getCode())
                .securityKey(UUID.randomUUID().toString())
                .build();
        machineDAO.insertSelective(machineEntity);
        response.setMachineId(machineEntity.getMachineId());
        return response;
    }

    @Override
    public DeleteMachineResponse deleteMachine(DeleteMachineRequest request) {
        DeleteMachineResponse response = new DeleteMachineResponse();
        int paramCount = paramDAO.countAnd(ParamInfoEntity.builder().machineId(request.getMachineId()).build());
        int hasAuthorityCount = authorityDAO.hasAuthorityOnMachine(request.getMachineId(), request.getLoginUserId());
        if (paramCount != hasAuthorityCount) {
            response.updateResult(ConfigResponseCode.NOT_AUTHORITY);
            return response;
        }
        MachineInfoEntity machineEntity = machineDAO.selectByPrimaryKey(request.getMachineId());
        if (machineEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        //记录快照日志
        loggerService.writeLog(OperateObjectEnum.MACHINE, request.getMachineId(), OperateTypeEnum.DELETE, request.getLoginUserId(), request.getLoginUserName());

        machineDAO.deleteByPrimaryKey(request.getMachineId());
        paramDAO.deleteAnd(ParamInfoEntity.builder().machineId(request.getMachineId()).build());
        return response;
    }

    @Override
    public RepairParamsResponse repairParams(RepairParamsRequest request) {
        RepairParamsResponse response = new RepairParamsResponse();
        MachineInfoEntity machineEntity = machineDAO.selectByPrimaryKey(request.getMachineId());
        if (machineEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        EnvironmentInfoEntity environmentInfoEntity = environmentDAO.selectByPrimaryKey(machineEntity.getEnvironmentId());
        if (environmentInfoEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        VersionInfoEntity versionInfoEntity = versionInfoDAO.selectByPrimaryKey(environmentInfoEntity.getVersionId());
        if (versionInfoEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        ProjectInfoEntity projectInfoEntity = projectDAO.selectByPrimaryKey(versionInfoEntity.getProjectId());
        if (projectInfoEntity == null) {
            response.updateResult(ConfigResponseCode.NO_DATA);
            return response;
        }
        String projectId = projectInfoEntity.getProjectId();
        String version = versionInfoEntity.getVersion();
        String environment = environmentInfoEntity.getEnvironmentName();
        String machine = machineEntity.getMachineName();

        //记录快照日志
        loggerService.writeLog(OperateObjectEnum.MACHINE, request.getMachineId(), OperateTypeEnum.DELETE, request.getLoginUserId(), request.getLoginUserName());

        int repairCount = paramDAO.repairParams(projectId, version, environment, machine);
        response.setRepairCount(repairCount);
        return response;
    }
}
